<?php

namespace App\Supports\Payment\Methods\Alibatch;

use Exception;
use Brick\Math\RoundingMode;
use App\Models\BatchWithdraw;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Supports\Payment\Methods\Method;
use Illuminate\Validation\ValidationException;
use App\Supports\Payment\Contracts\MethodTransfer;

class TransferWithdraw extends Method implements MethodTransfer
{
	/**
	 * @param BatchWithdraw | null $batch
	 * @param Collection | null $data
	 */
	public function validate($batch = null, $data = null)
	{
		$active = cashier('alibatch')->findActive();
		$active = big_decimal($active);

		if ($data->isEmpty()) {
			throw ValidationException::withMessages(['err' => '批量提现数据不能为空']);
		}
		if ($active->isLessThan($batch->batch_amount)) {
			throw ValidationException::withMessages(['err' => '支付宝账户可用余额不足']);
		}
	}

	/**
	 * @param BatchWithdraw | null $batch
	 * @param Collection | null $data
	 * @return array
	 */
	public function info($batch = null, $data = null)
	{
		$lists = [];

		if ($data->isNotEmpty()) {
			foreach ($data as $datum) {
				$lists[] = [
					'out_biz_no' => 'withdraw_'.$datum->number,
					'trans_amount' => big_decimal($datum->actual_amount)->toScale(2, RoundingMode::HALF_UP),
					'payee_info' => [
						'identity' => $datum->user->alipay_user_id,
						'identity_type' => 'ALIPAY_USER_ID',
					]
				];
			}
		}
		return [
			'out_batch_no' => $batch->batch_number,
			'total_trans_amount' => big_decimal($batch->batch_amount)->toScale(2, RoundingMode::HALF_UP),
			'total_count' => $batch->batch_count,
			'product_code' => 'BATCH_API_TO_ACC_NO_PWD',
			'biz_scene' => 'MESSAGE_BATCH_PAY',
			'trans_order_list' => $lists,
			'order_title' => '会员余额提现',
		];
	}

	protected function createBatchRecord(Collection $withdraws)
	{
		return DB::transaction(function () use ($withdraws) {

			$batchCount = $withdraws->count();

			$batchAmount = $withdraws->sum('actual_amount');

			$batch = BatchWithdraw::create([
				'batch_count' => $batchCount,
				'batch_amount' => $batchAmount,
				'payer' => 'alipay',
				'payer_id' => ($this->channel->config())['pid']
			]);

			foreach ($withdraws as $withdraw) {
				$withdraw->update(['batch_withdraw_id' => $batch->id]);
			}

			return $batch;
		});
	}

	protected function updateBatchRecord(BatchWithdraw $batch, $result)
	{
		if($result->code == 10000) {
			foreach($batch->withdraws as $withdraw){
				$fee = $withdraw->user->preFreeWithdrawQuotaAmount($withdraw->target_amount);
				$withdraw->user()->update(['pre_free_withdraw_quota' => $fee]);
			}
			$batch->update(['ali_batch_id' => $result->batch_trans_id, 'status' => 'success']);
		} elseif ($result->code == 20000) {
			$batch->update(['ali_batch_id' => $result->batch_trans_id, 'status' => 'retry']);
		} elseif ($result->code == 40004 and $result->sub_code == 'SYSTEM_ERROR') {
			$batch->update(['ali_batch_id' => $result->batch_trans_id, 'status' => 'retry']);
		} elseif ($result->code == 40004 and $result->sub_code == 'UNKNOWN_ERROR') {
			$batch->update(['ali_batch_id' => $result->batch_trans_id, 'status' => 'retry']);
		} else {
			$batch->update(['ali_batch_id' => $result->batch_trans_id, 'status' => 'failed']);
		}
	}

	/**
	 * @param BatchWithdraw | null $batch
	 * @param Collection | null $data
	 */
	public function transfer($data = null)
	{
		$batch = $this->createBatchRecord($data);

		$this->validate($batch, $data);

		try {
			$info = $this->info($batch, $data);
			$result = $this->channel->transfer($info);

			if (empty($result->code)) {
				abort(403, "{$result->code} - 批量提现异常");
			}

			$this->updateBatchRecord($batch, $result);

		} catch (Exception $exception) {
			$failedReason = $exception->getCode().$exception->getMessage();
			$batch->update(['remark' => "异常: {$failedReason}", 'status' => 'failed']);
		}
	}
}
